def createInstance(self, dom, recreate=0):
"""Create a block device controller for a domain.
- dom domain
- recreate if true it's a recreate (after xend restart)
+ @param dom: domain
+ @type dom: int
+ @param recreate: if true it's a recreate (after xend restart)
+ @type recreate: bool
+ @return: deferred
+ @rtype: twisted.internet.defer.Deferred
"""
d = defer.Deferred()
blkif = self.getInstanceByDom(dom)
def getDomainDevices(self, dom):
"""Get the block devices for a domain.
- dom domain
-
- returns devices
+ @param dom: domain
+ @type dom: int
+ @return: devices
+ @rtype: [device]
"""
blkif = self.getInstanceByDom(dom)
return (blkif and blkif.getDevices()) or []
def getDomainDevice(self, dom, vdev):
"""Get a block device from a domain.
- dom domain
- vdev device index
-
- returns device
+ @param dom: domain
+ @type dom: int
+ @param vdev: device index
+ @type vedv: int
+ @return: device
+ @rtype: device
"""
blkif = self.getInstanceByDom(dom)
return (blkif and blkif.getDevice(vdev)) or None
def setControlDomain(self, dom, recreate=0):
"""Set the back-end block device controller domain.
- dom domain
- recreate if true it's a recreate (after xend restart)
+ @param dom: domain
+ @type dom: int
+ @param recreate: if true it's a recreate (after xend restart)
+ @type recreate: int
"""
if self.dom == dom: return
self.deregisterChannel()
def getControlDomain(self):
"""Get the back-end block device controller domain.
+
+ @return: domain
+ @rtype: int
"""
return self.dom
def reattachDevice(self, dom, vdev):
"""Reattach a device (on changing control domain).
- dom domain
- vdev device index
+ @param dom: domain
+ @type dom: int
+ @param vdev: device index
+ @type vdev: int
"""
blkif = self.getInstanceByDom(dom)
if blkif:
def devicesAttached(self):
"""Check if all devices are attached.
+
+ @return: true if all devices attached
+ @rtype: bool
"""
attached = 1
for blkif in self.getInstances():
return attached
def reattached(self):
- """Notify all block interface we have been reattached
+ """Notify all block interfaces we have been reattached
(after changing control domain).
"""
for blkif in self.getInstances():
blkif.reattached()
def respond_be_create(self, msg, d):
+ """Response handler for a be_create message.
+ Calls I{d} with the block interface created.
+
+ @param msg: message
+ @type msg: xu message
+ @param d: deferred to call
+ @type d: Deferred
+ """
print 'respond_be_create>'
val = unpackMsg('blkif_be_create_t', msg)
blkif = self.getInstanceByDom(val['domid'])
d.callback(blkif)
def respond_be_connect(self, msg):
+ """Response handler for a be_connect message.
+
+ @param msg: message
+ @type msg: xu message
+ """
print 'respond_be_connect>', self
val = unpackMsg('blkif_be_connect_t', msg)
blkif = self.getInstanceByDom(val['domid'])
pass
def respond_be_vbd_create(self, msg, d):
+ """Response handler for a be_vbd_create message.
+ Tries to grow the vbd, and passes the deferred I{d} on for
+ the grow to call.
+
+ @param msg: message
+ @type msg: xu message
+ @param d: deferred to call
+ @type d: Deferred
+ """
print 'recv_be_vbd_create>', self
val = unpackMsg('blkif_be_vbd_create_t', msg)
blkif = self.getInstanceByDom(val['domid'])
pass
def respond_be_vbd_grow(self, msg, d):
+ """Response handler for a be_vbd_grow message.
+
+ @param msg: message
+ @type msg: xu message
+ @param d: deferred to call
+ @type d: Deferred or None
+ """
print 'recv_be_vbd_grow>', self
val = unpackMsg('blkif_be_vbd_grow_t', msg)
# Check status?
self.reattachDevice(val['domid'], val['vdevice'])
def recv_be_driver_status_changed(self, msg, req):
+ """Request handler for be_driver_status_changed messages.
+
+ @param msg: message
+ @type msg: xu message
+ @param req: request flag (true if the msg is a request)
+ @type req: bool
+ """
print 'recv_be_driver_status_changed>', self, req
val = unpackMsg('blkif_be_driver_status_changed_t', msg)
status = val['status']
return self.devices.get(vdev)
def addDevice(self, vdev, mode, segment):
+ """Add a device to the device table.
+
+ @param vdev: device index
+ @type vdev: int
+ @param mode: read/write mode
+ @type mode: string
+ @param segment: segment
+ @type segment: int
+ @return: device
+ @rtype: BlkDev
+ """
if vdev in self.devices: return None
dev = BlkDev(self, vdev, mode, segment)
self.devices[vdev] = dev
def attachDevice(self, vdev, mode, segment, recreate=0):
"""Attach a device to the specified interface.
- vdev device index
- mode read/write mode
- segment segment
- recreate if true it's being recreated (after xend restart)
-
- returns deferred
+ @param vdev: device index
+ @type vdev: int
+ @param mode: read/write mode
+ @type mode: string
+ @param segment: segment
+ @type segment: int
+ @param recreate: if true it's being recreated (after xend restart)
+ @type recreate: bool
+ @return: deferred
+ @rtype: Deferred
"""
dev = self.addDevice(vdev, mode, segment)
if not dev: return -1
import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
from xen.lowlevel import xu
-from messages import msgTypeName
+from messages import msgTypeName, printMsg
VIRQ_MISDIRECT = 0 # Catch-all interrupt for unbound VIRQs.
VIRQ_TIMER = 1 # Timebase update, and/or requested timeout.
def getLocalPort(self):
"""Get the local port.
+
+ @return: local port
+ @rtype: int
"""
if self.closed: return -1
return self.port.local_port
def getRemotePort(self):
"""Get the remote port.
+
+ @return: remote port
+ @rtype: int
"""
if self.closed: return -1
return self.port.remote_port
def registerDevice(self, types, dev):
"""Register a device controller.
- @param types message types the controller handles
- @param dev device controller
+ @param types: message types the controller handles
+ @type types: array of ints
+ @param dev: device controller
"""
if self.closed: return
self.devs.append(dev)
def deregisterDevice(self, dev):
"""Remove the registration for a device controller.
- @param dev device controller
+ @param dev: device controller
"""
if dev in self.devs:
self.devs.remove(dev)
def getDevice(self, type):
"""Get the device controller handling a message type.
- @param type message type
- @returns controller or None
+ @param type: message type
+ @type type: int
+ @return: controller or None
+ @rtype: device controller
"""
return self.devs_by_type.get(type)
def getMessageType(self, msg):
"""Get a 2-tuple of the message type and subtype.
+
+ @param msg: message
+ @type msg: xu message
+ @return: type info
+ @rtype: (int, int)
"""
hdr = msg.get_header()
return (hdr['type'], hdr.get('subtype'))
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+"""General support for controllers, which handle devices
+for a domain.
+"""
from twisted.internet import defer
defer.Deferred.debug = 1
import channel
-from messages import msgTypeName
+from messages import msgTypeName, printMsg
-DEBUG=0
+DEBUG = 0
class OutOfOrderError(RuntimeError):
- """Error reported when a response arrives out of order.
+ """Error reported when a response message arrives out of order.
"""
pass
class Responder:
- """Handler for a response to a message.
+ """Handler for a response to a message with a specified id.
"""
def __init__(self, mid, deferred):
"""Create a responder.
- mid message id of response to handle
- deferred deferred object holding the callbacks
+ @param mid: message id of response to handle
+ @type mid: int
+ @param deferred: deferred object holding the callbacks
+ @type deferred: Deferred
"""
self.mid = mid
self.deferred = deferred
def responseReceived(self, msg):
+ """Entry point called when a response message with the right id arrives.
+ Calls callback on I{self.deferred} with the message.
+
+ @param msg: response message
+ @type msg: xu message
+ """
if self.deferred.called: return
self.deferred.callback(msg)
def error(self, err):
+ """Entry point called when there has been an error.
+ Calls errback on I{self.deferred} with the error.
+
+ @param err: error
+ @type err: Exception
+ """
if self.deferred.called: return
self.deferred.errback(err)
class CtrlMsgRcvr:
"""Abstract class for things that deal with a control interface to a domain.
-
- Instance variables:
-
- dom : the domain we are a control interface for
- majorTypes: list of major message types we are interested in
- subTypes : mapping of message subtypes to methods
+ Once I{registerChannel} has been called, our message types are registered
+ with the channel to the domain. The channel will call I{requestReceived}
+ when a request arrives, or I{responseReceived} when a response arrives,
+ if they have one of our message types.
+
+ @ivar dom: the domain we are a control interface for
+ @type dom: int
+ @ivar majorTypes: major message types we are interested in
+ @type majorTypes: [int]
+ @ivar subTypes: mapping of message subtypes to methods
+ @ivar subTypes: {int:method}
+ @ivar timeout: timeout (in seconds) for message handlers
+ @type timeout: int
- channel : channel to the domain
- idx : channel index
+ @ivar channel: channel to the domain
+ @type channel: Channel
+ @ivar idx: channel index
+ @ivar idx: string
+ @ivar responders: table of message response handlers
+ @type responders: {int:Responder}
"""
-
def __init__(self):
self.channelFactory = channel.channelFactory()
self.majorTypes = [ ]
self.channel = None
self.idx = None
self.responders = []
- # Timeout (in seconds) for deferreds.
self.timeout = 10
def setTimeout(self, timeout):
self.timeout = timeout
def requestReceived(self, msg, type, subtype):
- """Dispatch a request to handlers.
-
- msg message
- type major message type
- subtype minor message type
+ """Dispatch a request message to handlers.
+ Called by the channel for requests with one of our types.
+
+ @param msg: message
+ @type msg: xu message
+ @param type: major message type
+ @type type: int
+ @param subtype: minor message type
+ @type subtype: int
"""
- msgid = msg.get_header()['id']
if DEBUG:
- print 'requestReceived>', self, msgid, msgTypeName(type, subtype)
+ print 'requestReceived>',
+ printMsg(msg, all=1)
method = self.subTypes.get(subtype)
if method:
method(msg, 1)
def responseReceived(self, msg, type, subtype):
"""Dispatch a response to handlers.
-
- msg message
- type major message type
- subtype minor message type
+ Called by the channel for responses with one of our types.
+
+ First looks for a message responder for the message's id.
+ See L{callResponders}, L{addResponder}.
+ If there is no responder, looks for a message handler for
+ the message type/subtype.
+
+ @param msg: message
+ @type msg: xu message
+ @param type: major message type
+ @type type: int
+ @param subtype: minor message type
+ @type subtype: int
"""
- msgid = msg.get_header()['id']
if DEBUG:
- print 'responseReceived>', self, msgid, msgTypeName(type, subtype)
+ print 'responseReceived>',
+ printMsg(msg, all=1)
if self.callResponders(msg):
return
method = self.subTypes.get(subtype)
def addResponder(self, mid, deferred):
"""Add a responder for a message id.
- The deferred is called with callback(msg) when a response
- with the given message id arrives. Responses are expected
+ The I{deferred} is called with callback(msg) when a response
+ with message id I{mid} arrives. Responses are expected
to arrive in order of message id. When a response arrives,
waiting responders for messages with lower id have errback
called with an OutOfOrder error.
- mid message id of response expected
- deferred a Deferred to handle the response
+ Responders have a timeout set and I{deferred} will error
+ on expiry.
- returns Responder
+ @param mid: message id of response expected
+ @type mid: int
+ @param deferred: handler for the response
+ @type deferred: Deferred
+ @return: responder
+ @rtype: Responder
"""
if self.timeout > 0:
deferred.setTimeout(self.timeout)
def callResponders(self, msg):
"""Call any waiting responders for a response message.
+ Looks for a responder registered for the message's id.
+ See L{addResponder}.
- msg response message
-
- returns 1 if there was a responder for the message, 0 otherwise
+ @param msg: response message
+ @type msg: xu message
+ @return: 1 if there was a responder for the message, 0 otherwise
+ @rtype : bool
"""
hdr = msg.get_header()
mid = hdr['id']
break
self.responders.pop()
if resp.mid < mid:
- print 'handleResponse> Out of order:', resp.mid, mid
+ print 'callResponders> Out of order:', resp.mid, mid
resp.error(OutOfOrderError())
else:
handled = 1
def registerChannel(self):
"""Register interest in our major message types with the
- channel to our domain.
+ channel to our domain. Once we have registered, the channel
+ will call requestReceived or responseReceived for our messages.
"""
self.channel = self.channelFactory.domChannel(self.dom)
self.idx = self.channel.getIndex()
def deregisterChannel(self):
"""Deregister interest in our major message types with the
- channel to our domain.
+ channel to our domain. After this the channel won't call
+ us any more.
"""
if self.channel:
self.channel.deregisterDevice(self)
def produceRequests(self):
"""Produce any queued requests.
- return number produced
+ @return: number produced
+ @rtype: int
"""
return 0
def writeRequest(self, msg, response=None):
"""Write a request to the channel.
- msg message
- response Deferred to handle the response (optional)
+ @param msg: request message
+ @type msg: xu message
+ @param response: response handler
+ @type response: Deferred
"""
if self.channel:
- if DEBUG: print 'CtrlMsgRcvr>writeRequest>', self, msg
+ if DEBUG:
+ print 'CtrlMsgRcvr>writeRequest>',
+ printMsg(msg, all=1)
if response:
self.addResponder(msg.get_header()['id'], response)
self.channel.writeRequest(msg)
print 'CtrlMsgRcvr>writeRequest>', 'no channel!', self
def writeResponse(self, msg):
- """Write a response to the channel.
+ """Write a response to the channel. This acknowledges
+ a request message.
+
+ @param msg: message
+ @type msg: xu message
"""
if self.channel:
- if DEBUG: print 'CtrlMsgRcvr>writeResponse>', self, msg
+ if DEBUG:
+ print 'CtrlMsgRcvr>writeResponse>',
+ printMsg(msg, all=0)
self.channel.writeResponse(msg)
else:
print 'CtrlMsgRcvr>writeResponse>', 'no channel!', self
class ControllerFactory(CtrlMsgRcvr):
- """Abstract class for factories creating controllers.
+ """Abstract class for factories creating controllers for a domain.
Maintains a table of instances.
- Instance variables:
-
- instances : mapping of index to controller instance
- dlist : list of deferreds
- dom : domain
+ @ivar instances: mapping of index to controller instance
+ @type instances: {int: Controller}
+ @ivar dom: domain
+ @type dom: int
"""
def __init__(self):
CtrlMsgRcvr.__init__(self)
self.instances = {}
- self.dlist = []
self.dom = 0
def addInstance(self, instance):
def createInstance(self, dom, recreate=0):
"""Create an instance. Define in a subclass.
+
+ @param dom: domain
+ @type dom: int
+ @param recreate: true if the instance is being recreated (after xend restart)
+ @type recreate: int
"""
raise NotImplementedError()